package com.qqtop10.manager.controller;

import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
import java.lang.reflect.Method;
import java.math.BigDecimal;
import java.security.MessageDigest;
import java.util.Date;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.UUID;

import javax.servlet.ServletContext;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

import org.codehaus.jackson.map.ObjectMapper;
import org.codehaus.jackson.map.annotate.JsonSerialize.Inclusion;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.multipart.MultipartHttpServletRequest;

import com.qqtop10.manager.model.Admin;
import com.qqtop10.manager.model.AdminRole;
import com.qqtop10.manager.model.FileInfo;
import com.qqtop10.manager.model.PagingArgs;
import com.qqtop10.manager.model.Perm;
import com.qqtop10.manager.model.Result;
import com.qqtop10.manager.service.AdminService;
import com.qqtop10.manager.service.RoleService;
import com.qqtop10.manager.utils.Jackson;
import com.qqtop10.manager.utils.PageInterface;
import com.qqtop10.manager.utils.oss.OSSFilePath;
import com.qqtop10.manager.utils.oss.OSSUploadUtils;

/**
 * 
 * @author ChenXinwei
 *
 */
public class BaseController {
	private Logger logger = LoggerFactory.getLogger(BaseController.class);
	protected static ObjectMapper objectMapper = new ObjectMapper();
	@Autowired
	private AdminService adminService;
	@Autowired
	private RoleService roleService;
	
	static {
		// 为null的字段不序列号
		objectMapper.setSerializationInclusion(Inclusion.NON_NULL);
	}

	protected static final char[] Digits = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E',
			'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z',
			'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u',
			'v', 'w', 'x', 'y', 'z', };
	/** 信息摘要算法5(md5)的实例 */
	protected final MessageDigest MessageDigest5;
	/** 信息摘要算法5(md5)的实例 */
	protected final MessageDigest SecureHashAlgorithm;
	protected final byte[] ByteBuffer = new byte[1024];
	protected final char[] CharBuffer = new char[128];
	public final int Code_Success = 0;
	public final int Code_Msg = 0;
	public final int Code_Error = 1;
	public final int Code_Exception = 2;

	/** Instance init block. */
	{
		try {
			MessageDigest5 = MessageDigest.getInstance("MD5");
			SecureHashAlgorithm = MessageDigest.getInstance("SHA1");
		} catch (Exception e) {
			throw new RuntimeException(e);
		}
	}

	private HttpServletRequest request;
	private HttpServletResponse response;

	public HttpServletRequest getRequest() {
		return this.request;
	}

	@ModelAttribute
	public void setRequest(HttpServletRequest request) {
		this.request = request;
	}

	public HttpServletResponse getResponse() {
		return response;
	}

	@ModelAttribute
	public void setResponse(HttpServletResponse response) {
		this.response = response;
	}

	public HttpSession getSession() {
		return request.getSession();
	}

	public ServletContext getContext() {
		return getSession().getServletContext();
	}

	public OutputStream getOutputStream() {
		try {
			return response.getOutputStream();
		} catch (IOException e) {
			return null;
		}
	}

	public InputStream getInputStream() {
		try {
			return request.getInputStream();
		} catch (IOException e) {
			return null;
		}
	}

	public Result ok(Object obj) {
		return new Result(Code_Success, obj);
	}

	public Result ok(String msg) {
		return new Result(Code_Msg, msg);
	}

	public Result ok(String msg, Object obj) {
		return new Result(Code_Success, msg, obj);
	}

	public Result html(Object obj) {
		getResponse().setContentType("text/html;charset=UTF-8");
		try {
			getOutputStream().write(Jackson.asJson(ok(obj)).getBytes("utf-8"));
			getOutputStream().close();
		} catch (Exception e) {
			return excep(e);
		}
		return ok("html");
	}

	public Result html(String msg) {
		getResponse().setContentType("text/html;charset=UTF-8");
		try {
			getOutputStream().write(Jackson.asJson(ok(msg)).getBytes("utf-8"));
			getOutputStream().close();
		} catch (Exception e) {
			return excep(e);
		}
		return ok("html");
	}

	public Result html(String msg, Object obj) {
		getResponse().setContentType("text/html;charset=UTF-8");
		try {
			getOutputStream().write(Jackson.asJson(ok(msg, obj)).getBytes("utf-8"));
			getOutputStream().close();
		} catch (Exception e) {
			return excep(e);
		}
		return ok("html");
	}

	public Result page(int count, Object obj) {
		Result result = new Result(Code_Success, obj);
		result.setTotalRecords(count);
		return result;
	}

	public Result err(String msg) {
		return new Result(Code_Error, msg);
	}

	public Result file(String fileName) {
		if (fileName == null) {
			return excep(new NullPointerException("fileName"));
		}
		if (getResponse() == null) {
			return excep(new NullPointerException("response"));
		}
		getResponse().setContentType("application/octet-stream");
		try (FileInputStream input = new FileInputStream(fileName)) {
			OutputStream output = getResponse().getOutputStream();
			byte[] buffer = new byte[1024];
			int readCount;
			while ((readCount = input.read(buffer)) != 0) {
				output.write(buffer, 0, readCount);
			}
		} catch (Exception e) {
			return excep(e);
		}
		return ok("file");
	}

	public Result file(String fileName, String name) {
		try {
			if (fileName == null) {
				return excep(new NullPointerException("fileName"));
			}
			if (getResponse() == null) {
				return excep(new NullPointerException("response"));
			}
			if (getRequest() == null) {
				return excep(new NullPointerException("request"));
			}
			setFileName(name);
			try (FileInputStream input = new FileInputStream(fileName)) {
				OutputStream output = getOutputStream();
				byte[] buffer = new byte[1024];
				int readCount;
				while ((readCount = input.read(buffer)) != 0) {
					output.write(buffer, 0, readCount);
				}
			}
			return ok("file");
		} catch (Exception e) {
			return excep(e);
		}
	}

	public Result file(InputStream input, String name) {
		try {
			if (input == null) {
				return excep(new NullPointerException("input"));
			}
			if (getResponse() == null) {
				return excep(new NullPointerException("response"));
			}
			if (getRequest() == null) {
				return excep(new NullPointerException("request"));
			}
			setFileName(name);
			OutputStream output = getOutputStream();
			byte[] buffer = new byte[1024];
			int readCount;
			while ((readCount = input.read(buffer)) != 0) {
				output.write(buffer, 0, readCount);
			}
			return ok("file");
		} catch (Exception e) {
			return excep(e);
		}
	}

	public void setFileName(String name) {
		try {
			String userAgent = getRequest().getHeader("User-Agent");
			if (userAgent.contains("MSIE") || userAgent.contains("Trident")) {
				name = java.net.URLEncoder.encode(name, "UTF-8");
			} else {
				name = new String(name.getBytes("UTF-8"), "ISO-8859-1");
			}
			getResponse().setHeader("Content-disposition", String.format("attachment; filename=\"%s\"", name));
			getResponse().setContentType("application/octet-stream");
			getResponse().setCharacterEncoding("UTF-8");
		} catch (Exception e) {
			throw new RuntimeException(e);
		}
	}

	public Result excep(Exception e) {
		return new Result(Code_Exception, e.getMessage());
	}

	public Date now() {
		return new Date(System.currentTimeMillis());
	}

	public Admin getLogind() {
		Admin admin;
		Object o=request.getSession().getAttribute("Logind");
		if (request == null || (admin = (Admin)o ) == null) {
			throw new RuntimeException("Big Error!!!");
		}
		return admin;
	}

	public String getLogindUuid() {
		return getLogind().getUuid();
	}

	public String getLogindName() {
		return getLogind().getAccount();
	}

	public String getPermCodes() {
		AdminRole adminRole = new AdminRole();
		adminRole.setAdmin_uuid(getLogind().getUuid());
		String perm_codes = "";
		if (getLogindName().equalsIgnoreCase("admin")) {
			PagingArgs pagingArgs = getPagingArgs();
			pagingArgs.set_limit(Integer.MAX_VALUE);
			List<Perm> array = roleService.allPerm(new Perm(), pagingArgs);
			for (Perm perm : array) {
				perm_codes += perm.getCode() + ",";
			}
		} else {
			List<AdminRole> roles = adminService.getAdminRole(adminRole);
			for (AdminRole role : roles) {
				perm_codes += role.getPerm_codes() + ",";
			}
		}
		return perm_codes;
	}

	public String newId() {
		UUID uUID = UUID.randomUUID();
		long low = uUID.getLeastSignificantBits();
		long high = uUID.getMostSignificantBits();
		return (digits(high >> 32, 8) + digits(high >> 16, 4) + digits(high, 4) + digits(low >> 48, 4)
				+ digits(low, 12));
	}

	private static String digits(long val, int digits) {
		long hi = 1L << (digits * 4);
		return Long.toHexString(hi | (val & (hi - 1))).substring(1);
	}

	@SuppressWarnings("deprecation")
	public Date getLastMonthFirstDay() {
		Date date = new Date(System.currentTimeMillis());
		date.setMonth(date.getMonth() - 1);
		date.setDate(1);
		date.setHours(0);
		date.setMinutes(0);
		date.setSeconds(0);
		return date;
	}

	@SuppressWarnings("deprecation")
	public Date getLastMonthLastDay() {
		Date date = new Date(System.currentTimeMillis());
		date.setDate(0);
		date.setHours(23);
		date.setMinutes(59);
		date.setSeconds(59);
		return date;
	}

	@SuppressWarnings("deprecation")
	public Date getCurrentMonthFirstDay() {
		Date date = new Date(System.currentTimeMillis());
		date.setDate(1);
		date.setHours(0);
		date.setMinutes(0);
		date.setSeconds(0);
		return date;
	}

	@SuppressWarnings("deprecation")
	public Date getYesterday() {
		Date date = new Date(System.currentTimeMillis());
		date.setDate(date.getDate() - 1);
		date.setHours(0);
		date.setMinutes(0);
		date.setSeconds(0);
		return date;
	}

	@SuppressWarnings("deprecation")
	public Date getToday() {
		Date date = new Date(System.currentTimeMillis());
		date.setHours(0);
		date.setMinutes(0);
		date.setSeconds(0);
		return date;
	}

	public PagingArgs getPagingArgs() {
		PagingArgs args = new PagingArgs();
		if (request == null) {
			args.set_limit(20);
			return args;
		}
		String pagenum = request.getParameter("pagenum");
		String pagesize = request.getParameter("pagesize");
		String sortdatafield = request.getParameter("sortdatafield");
		String sortorder = request.getParameter("sortorder");
		if (pagesize != null && pagesize.length() != 0) {
			args.set_limit(Integer.parseInt(pagesize));
			if (pagenum != null && pagenum.length() != 0) {
				args.set_offset(Integer.parseInt(pagenum) * args.get_limit());
			}
		} else {
			args.set_limit(20);
		}
		if (sortdatafield != null && sortdatafield.length() != 0) {
			if (sortorder == null || sortdatafield.length() == 0) {
				sortorder = "asc";
			}
			args.set_sorters(new String[] { sortdatafield + " " + sortorder });
		}else{
			sortdatafield = "id";
			sortorder = "desc";
			args.set_sorters(new String[] { sortdatafield + " " + sortorder });
		}
		return args;
	}

	@SuppressWarnings("deprecation")
	private Object conver(Class<?> type, String val) {
		if (type == String.class) {
			return val;
		}
		if (type == boolean.class || type == Boolean.class) {
			return Boolean.valueOf(val);
		}
		if (type == byte.class || type == Byte.class) {
			return Byte.valueOf(val);
		}
		if (type == short.class || type == Short.class) {
			return Short.valueOf(val);
		}
		if (type == char.class || type == Character.class) {
			return val == null || val.length() == 0 ? null : (Character) val.charAt(0);
		}
		if (type == int.class || type == Integer.class) {
			return Integer.valueOf(val);
		}
		if (type == float.class || type == Float.class) {
			return Float.valueOf(val);
		}
		if (type == long.class || type == Long.class) {
			return Long.valueOf(val);
		}
		if (type == double.class || type == Double.class) {
			return Double.valueOf(val);
		}
		if (type == Date.class) {
			return Date.parse(val);
		}
		if (type == BigDecimal.class) {
			return new BigDecimal(val);
		}
		return val;

	}

	public MultipartFile getFile(String name) {
		return request instanceof MultipartHttpServletRequest ? ((MultipartHttpServletRequest) request).getFile(name)
				: null;
	}

	public void fill(Object obj) {
		if (obj == null || request == null) {
			return;
		}
		Class<?> type = obj.getClass();
		Enumeration<?> enumeration = request.getParameterNames();
		while (enumeration.hasMoreElements()) {
			String name = (String) enumeration.nextElement();
			String name2 = Character.toUpperCase(name.charAt(0)) + name.substring(1);
			String getMethodName = "get" + name2;
			String setMethodName = "set" + name2;
			try {
				Method getMethod = type.getMethod(getMethodName);
				Class<?> paramType = getMethod.getReturnType();
				Method setMethod = type.getMethod(setMethodName, paramType);
				setMethod.setAccessible(true);
				setMethod.invoke(obj, conver(paramType, request.getParameter(name)));
			} catch (Exception e) {
				continue;
			}
		}
	}

	public String save(MultipartFile file) {
		if (file == null || file.isEmpty()) {
			throw new NullPointerException("file");
		}
		try {
			String fileId = newId();
			String oldName = file.getOriginalFilename();
			oldName = oldName != null && oldName.length() != 0 && oldName.lastIndexOf('.') != -1
					? oldName.substring(oldName.lastIndexOf('.')) : "";
			// 保存文件至OSS，原有的保存至本地的代码可舍弃
			OSSUploadUtils ossUploadUtils = new OSSUploadUtils();
			// 图片上传OSS
			ossUploadUtils.uploadFile(OSSFilePath.USUALLYSAVEPATHPREFIX + fileId + oldName, file);
			// 关闭OSS客户端
			ossUploadUtils.closeOssClient();
			// File destFile = new File(FolderPath.getRootPath() +
			// "/images/files/");
			// destFile.mkdirs();
			// file.transferTo(new File(destFile, fileId + oldName));
			return OSSFilePath.OSSDOMAIN + "/images/files/" + fileId + oldName;
		} catch (Exception e) {
			throw new RuntimeException(e);
		}
	}

	public FileInfo saveShow(MultipartFile file, Integer type) {
		if (file == null || file.isEmpty()) {
			throw new NullPointerException("file");
		}
		try {
			String name = file.getOriginalFilename();
			String format = name.substring(name.lastIndexOf(".") - 1);
			String fileId = newId();
			// String serverPath = FolderPath.getShowPirtruePath();
			// File destFile = new File(serverPath + fileId + format);
			// destFile.mkdirs();
			// file.transferTo(destFile);
			FileInfo fileInfo = new FileInfo();
			fileInfo.setId(fileId);
			fileInfo.setName(file.getOriginalFilename());
			fileInfo.setSize(file.getSize());
			// 保存文件至OSS，原有的保存至本地的代码可舍弃
			OSSUploadUtils ossUploadUtils = new OSSUploadUtils();
			// 图片上传OSS
			ossUploadUtils.uploadFile(OSSFilePath.ADVERTISEPATH + fileId + format, file);
			if (type!=null&& type == 4) {
				ossUploadUtils.uploadFile(OSSFilePath.SEARCHRIGHTADVERTISE + fileId + format, file);
				fileInfo.setUrl(OSSFilePath.OSSDOMAIN + "/images/add/show/" + fileId + format);
			}else{
				fileInfo.setUrl(OSSFilePath.OSSDOMAIN + "/images/show/" + fileId + format);
			}
			// 关闭OSS客户端
			ossUploadUtils.closeOssClient();
			
			return fileInfo;
		} catch (Exception e) {
			throw new RuntimeException(e);
		}
	}

	public boolean isNull(String st) {
		return !(st != null && st.length() != 0);
	}

	/** 获得一段字符串的md5值 */
	public String md5(String src) {
		return digest(src, MessageDigest5);
	}

	/** 获得一段字符串的sha1值 */
	public String sha1(String src) {
		return digest(src, SecureHashAlgorithm);
	}

	private int utf8(String chars, int offset, int length, byte[] bytes, int begin) {
		length += offset;
		int index = begin;
		for (; offset != length; ++offset) {
			char chr = chars.charAt(offset);
			if (chr <= 0x7f) {
				bytes[index++] = (byte) chr;
			} else if (chr <= 0x7ff) {
				bytes[index++] = (byte) (chr >>> 6 | 0xc0);
				bytes[index++] = (byte) (chr & 0x3f | 0x80);
			} else {
				bytes[index++] = (byte) (chr >>> 12 | 0xe0);
				bytes[index++] = (byte) (chr >>> 6 & 0x3f | 0x80);
				bytes[index++] = (byte) (chr & 0x3f | 0x80);
			}
		}
		return index - begin;
	}

	private String digest(String src, MessageDigest mode) {
		try {
			int length = utf8(src, 0, src.length(), ByteBuffer, 0);
			mode.update(ByteBuffer, 0, length);
			length = mode.digest(ByteBuffer, 0, 1024);
			for (int i = 0; i < length; i++) {
				CharBuffer[i << 1] = Digits[(ByteBuffer[i] & 0xF0) >> 4];
				CharBuffer[(i << 1) + 1] = Digits[ByteBuffer[i] & 0x0F];
			}
			return new String(CharBuffer, 0, length << 1);
		} catch (Exception e) {
			throw new RuntimeException(e);
		}
	}

	/**
	 * 将返回结果转Json数据
	 * 
	 * @param result
	 * @param callback
	 * @return
	 */
	public static String result2Json(/* Map<String, Object> */Object result, String callback) {
		StringBuffer sb = new StringBuffer();
		String json = null;
		try {
			json = objectMapper.writeValueAsString(result);
			if (callback != null && !callback.trim().equals("")) {
				if (callback.startsWith("script-")) {
					sb.append("<script>");
					sb.append(callback.substring(7) + "(");
					sb.append(json);
					sb.append(");");
					sb.append("</script>");
				} else {
					sb.append(callback + "(");
					sb.append(json);
					sb.append(");");
				}
			} else {
				sb.append(json);
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
		return sb.toString();
	}

	// 分页
	public String page(Map<String, Object> extend, PageInterface pageService, HttpServletRequest request)
			throws IOException {
		Map<String, Object> result = null;
		Map<String, Object> map = null;
		StringBuffer limit = null;
		// 回调函数
		String callback = null;
		// 临时变量 第几页
		String spagenum = null;
		// 临时变量 每页数量
		String spagesize = null;
		// 第几页
		int pagenum = 0;
		// 每页数量
		int pagesize = 0;
		// 总数
		int count = 0;
		try {
			result = new HashMap<>();
			map = new HashMap<>();
			limit = new StringBuffer();
			// 获取回调函数名称
			callback = request.getParameter("callback");
			// 获取 第几页
			spagenum = request.getParameter("pagenum");
			// 获取 每页数量
			spagesize = request.getParameter("pagesize");
			if (spagenum == null || spagenum.trim().equals("") || spagesize == null || spagesize.trim().equals("")) {
				result.put("code", 99);
				result.put("msg", "获取数据列表失败：分页参数不允许为空");
				logger.info("获取数据列表失败：分页参数不允许为空");
			} else {
				pagenum = Integer.parseInt(spagenum);
				pagesize = Integer.parseInt(spagesize);
				// 先添加查询条件，用于统计数量
				map.putAll(extend);
				// 先统计数量
				count = pageService.count(map);
				// 将总数量保存
				result.put("totalRecords", count);
				// 计算最多有几页
				count = count % pagesize == 0 ? count / pagesize : count / pagesize + 1;
				// 返回总页数
				result.put("totalPage", count);
				// 如果提交的页数比总实际页数大，那就等于实际总页数
				if (pagenum > count) {
					pagenum = count;
				}
				// 当前页不能等于0
				pagenum = pagenum <= 0 ? 1 : pagenum;
				// 返回 -- 当前页数
				result.put("pagenum", count == 0 ? 0 : pagenum);
				// 拼接sql分页字符串
				limit.append(" LIMIT ");
				// 计算该页从第几条数据开始
				limit.append((pagenum - 1) * pagesize);
				limit.append(",");
				// 共显示几条
				limit.append(pagesize);
				map.put("limit", limit);
				result.put("data", pageService.selectBySelective(map));
				result.put("code", 1);
				result.put("msg", "获取数据列表成功！");
				logger.info("获取数据列表成功！");
			}
		} catch (Exception e) {
			e.printStackTrace();
			result.put("code", 90);
			result.put("msg", "获取数据列表失败！");
			result.remove("count");
			result.remove("totalPage");
			result.remove("pagenum");
			logger.error("获取数据列表失败！");
		}
		return result2Json(result, callback);
	}

	/**
	 * 
	 * @param srcStr
	 *            需要转UTF8编码的源字符串
	 * @return UTF8编码后的字符串
	 */
	protected String getParameter(String srcStr) {
		String str = "";
		try {
			str = new String(srcStr.getBytes("iso8859-1"), "UTF-8");
		} catch (UnsupportedEncodingException e) {
			e.printStackTrace();
		}
		return str;
	}
}
